package com.suray.wcs.service.thread;

import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.entity.PlcDeviceDB;
import com.suray.basic.wcs.plc.mapper.PlcDeviceDBMapper;
import com.suray.basic.wcs.plc.pojo.oper.single.DeviceInterface;
import com.suray.basic.wcs.plc.pojo.oper.single.MonomerConveyorOper;
import com.suray.basic.wcs.plc.pojo.oper.single.ScanOper;
import com.suray.basic.wcs.plc.pojo.oper.single.ShapeOper;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.enums.NotificationTypeEnum;
import com.suray.wcs.service.enums.PortModel;
import com.suray.wcs.service.init.SystemInit;
import com.suray.wcs.service.plc.SingleBarCodeScanner;
import com.suray.wcs.service.system.entity.PortDB;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.PortDBServiceImpl;
import com.suray.wcs.service.test.base.BaseThread;
import com.suray.wcs.service.thread.process.PlcConveryTask;
import com.suray.wcs.service.util.WcsUtil;

import java.io.IOException;

/**
 * 扫码流程
 */
public class ScanTaskThread extends BaseThread {
    private static PlcDeviceDBMapper plcdevicedbMapper = SpringContextHolder.getBean(PlcDeviceDBMapper.class);
    private static NodeDBServiceImpl nodeDBService = SpringContextHolder.getBean(NodeDBServiceImpl.class);
    private static PortDBServiceImpl portDBService = SpringContextHolder.getBean(PortDBServiceImpl.class);

    private PortDB portDB;

    public ScanTaskThread(PortDB portDB) {
        super(portDB.getPortName() + "扫码输送", 1000, ScanTaskThread.class);

        this.portDB = portDB;
    }

    @Override
    protected void init() {
        LoggerUtil.info("库口：" + portDB.getPortName() + "扫码输送启动", this.getClass());
        super.init();
    }

    @Override
    protected void process() {
        try {
            //更新数据库库口数据
            portDB = SystemInit.PORTS.get(portDB.getPortId());

            if (portDB.getPortMode() == PortModel.OUT_PORT.getValue()) {
                return;
            }

            if (portDB.getStations() == null) {
                return;
            }

            if (!portDB.getStations().contains("-")) {
                LoggerUtil.info("库口：" + portDB.getPortName() + "工位配置不正确:" + portDB.getStations(),
                        this.getClass());
                return;
            }

            String[] stationIds = portDB.getStations().split("-");
            PlcDeviceDB startPlcDb = plcdevicedbMapper.selectById(stationIds[0]);
            PlcDeviceDB endPlcDb = plcdevicedbMapper.selectById(stationIds[1]);

            if (startPlcDb == null || endPlcDb == null) {
                LoggerUtil.info("库口：" + portDB.getPortName() + " 输送设备未配置", this.getClass());
                return;
            }

            DeviceInterface startDevice = (DeviceInterface) Plc.deviceBaseNameMap.get(startPlcDb.getDeviceName());
            DeviceInterface endDevice = (DeviceInterface) Plc.deviceBaseNameMap.get(endPlcDb.getDeviceName());

            if (startDevice == null || endDevice == null) {
                LoggerUtil.info("库口：" + portDB.getPortName() + " 输送设备不在线", this.getClass());
                return;
            }

            MonomerConveyorOper monomerConveyorOper = (MonomerConveyorOper) startDevice;
            ScanOper scanOper = null;
            ShapeOper shapeOper = null;
            if (portDB.getScanName() != null) {
                scanOper = (ScanOper) Plc.deviceBaseNameMap.get(portDB.getScanName());
            }
            if (portDB.getShapeName() != null) {
                shapeOper = (ShapeOper) Plc.deviceBaseNameMap.get(portDB.getShapeName());
            }

            if (startDevice == null || endDevice == null) {
                return;
            }

            if (!checkInCargoSignal(monomerConveyorOper)) {
                return;
            }

            Boolean scanEnd = SingleBarCodeScanner.scannerMap.get(portDB);
            if (scanEnd == null) {
                startDevice.setDeviceStatus(portDB.getPortName() + "等待扫码流程启动");
                return;
            }

            if (SingleBarCodeScanner.scannerMap.get(portDB)) {
                startDevice.setDeviceStatus(portDB.getPortName() + "扫码完成信号未清除");
                return;
            }

            if (!startDevice.hasCargo()) {
                startDevice.setDeviceStatus(portDB.getPortName() + " 起点未检测到货物，无法扫码");
                return;
            }

            //扫码器开启
            boolean flag = false;
            if (scanOper != null) {
                scanOper.openScan();
                flag = true;
            }

            //外形检测开启
            if (!flag && shapeOper != null) {
                shapeOper.openShape();
            }
            if (checkInCargoSignal(monomerConveyorOper)) {
                clearInCargoSignal(monomerConveyorOper);
            }
            try {
                converyTransCargo(startDevice, endDevice);
            } catch (Exception e) {
                closeDevice(shapeOper, scanOper);
                throw e;
            }
            //输送任务完成，写入扫码结束，进入扫码入库流程
            WcsUtil.changeNodeCargoStatus(endDevice.getCoord(), nodeDBService, true);
            closeDevice(shapeOper, scanOper);

            int tick = 10;
            if (scanOper != null) {
                while (!scanOper.isScanCanRead() && !scanOper.isScanError()) {
                    WcsFuncUtil.delay(300);
                    if (tick > 0) {
                        tick--;
                    } else {
                        LoggerUtil.info("扫码流程结束，扫码器不可读:" + scanOper.getDeviceName(), this.getClass());
                        break;
                    }
                }
            } else if (shapeOper != null) {
                while (!shapeOper.isShapeCanRead()) {
                    WcsFuncUtil.delay(300);
                    if (tick > 0) {
                        tick--;
                    } else {
                        LoggerUtil.info("普通包材出库口，外形检测完毕，但是外形检测不可读:" + shapeOper.getDeviceName(),
                                this.getClass());
                        break;
                    }
                }
            }

            SingleBarCodeScanner.scannerMap.put(portDB, true);
            LoggerUtil.info("扫码完成:" + portDB, this.getClass());

            tick = 6;
            while (checkInCargoSignal(monomerConveyorOper)) {
                if (tick > 0) {
                    if (tick % 2 == 0) {
                        clearInCargoSignal(monomerConveyorOper);
                    }
                    tick--;
                } else {
                    LoggerUtil.warn("PLC入库信号未清除成功", this.getClass());
                    break;
                }
                WcsUtil.delay(1000);
            }
        } catch (IOException e) {
            LoggerUtil.warn(portDB.getPortName() + " 通讯异常", this.getClass());
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, this.getClass());
            WcsUtil.notification("扫码入库流程异常：" + e.getMessage(), NotificationTypeEnum.ERROR);
        }
    }

    private void converyTransCargo(DeviceInterface startDevice, DeviceInterface endDevice) throws IOException {
        PlcConveryTask.plcTransCargo(startDevice, endDevice, null, 9999);
    }

    private void closeDevice(ShapeOper shapeOper, ScanOper scanOper) throws IOException {
        //外形检测关闭
        boolean flag = false;
        if (shapeOper != null) {
            shapeOper.closeShape();
            flag = true;
        }
        //扫码器关闭
        if (!flag && scanOper != null) {
            scanOper.closeScan();
        }

    }

    /**
     * 清除入库信号
     * @param monomerConveyorOper
     */
    private void clearInCargoSignal(MonomerConveyorOper monomerConveyorOper) throws IOException {
        monomerConveyorOper.clearAskInCargo();
    }

    /**
     * 检测入库信号
     * @return
     * @param monomerConveyorOper
     */
    private boolean checkInCargoSignal(MonomerConveyorOper monomerConveyorOper) {
        return monomerConveyorOper.getIfAskInCargo();
    }
}
